/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.huawei.spare.part.replace.views.prepare.download;

import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.huawei.spare.part.replace.framework.SmartContentPresenter;
import com.huawei.spare.part.replace.framework.SmartDataBus;
import com.huawei.spare.part.replace.framework.SmartDatabase;
import com.huawei.spare.part.replace.framework.SmartRouter;
import com.huawei.spare.part.replace.models.DownloadPackage;
import com.huawei.spare.part.replace.models.DownloadTask;
import com.huawei.spare.part.replace.models.InstallPackage;
import com.huawei.spare.part.replace.models.Project;
import com.huawei.spare.part.replace.models.Solution;
import com.huawei.spare.part.replace.models.Switch;
import com.huawei.spare.part.replace.models.SwitchMatchedPackage;
import com.huawei.spare.part.replace.models.constants.Plane;
import com.huawei.spare.part.replace.rx.RxOkHttp;
import com.huawei.spare.part.replace.views.widgets.cell.TooltipTextFieldTableCell;
import com.huawei.spare.part.replace.views.widgets.toast.Toast;
import io.reactivex.Observable;
import io.reactivex.observers.DisposableObserver;
import io.reactivex.rxjavafx.observables.JavaFxObservable;
import io.reactivex.rxjavafx.schedulers.JavaFxScheduler;
import io.reactivex.schedulers.Schedulers;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javafx.application.Platform;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.binding.StringBinding;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.ProgressBarTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javax.swing.filechooser.FileSystemView;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Woo
 */
public class DownloadPresenter extends SmartContentPresenter {

  private static final Logger log = LoggerFactory.getLogger(DownloadPresenter.class);

  public static final String CPLD = "CPLD";
  public static final String BMC = "BMC";

  @FXML TableView downloadTable;
  @FXML TableColumn<DownloadTask, String> softwareColumn;
  @FXML TableColumn<DownloadTask, String> versionColumn;
  @FXML TableColumn<DownloadTask, String> packageNameColumn;
  @FXML TableColumn<DownloadTask, Double> progressColumn;
  @FXML TableColumn<DownloadTask, Void> buttonsColumn;
  @FXML VBox tipsBox;

  Optional<InstallPackage> fabricPackage = Optional.empty();
  Optional<InstallPackage> basePackage = Optional.empty();
  Optional<InstallPackage> cpldPackage = Optional.empty();
  Optional<InstallPackage> bmcPackage = Optional.empty();

  DownloadTask fabricDownloadTask;
  DownloadTask baseDownloadTask;
  DownloadTask cpldDownloadTask;
  DownloadTask bmcDownloadTask;

  Project project;
  SwitchMatchedPackage matchedPackage;
  String finalFabricVersion;
  String finalBaseVersion;
  //    BooleanProperty ok = new SimpleBooleanProperty(true);
  ObservableList<DownloadTask> downloadTasks = FXCollections.observableArrayList();
  ObservableList<String> tips = FXCollections.observableArrayList();
  BooleanBinding allDownloadTaskCompleted;

  @Override
  public void initialize() {
    project = SmartDataBus.get().getProject();
    matchedPackage = project.getDefective().getMatchedPackage();
    SmartRouter.get().nextStepButton().setDisable(true);       // 禁用下一步按钮

    initializeTableView();  // 初始化表格展示设置
    initialInstallPackages();  // 查找设置所需的安装包
    initialTableData();     // 设置表格显示数据
    initialTipsBox();       // 显示提示信息

    Platform.runLater(() -> {
      initialFinishedObserver();  // 设置操作完成观察
    });
  }

  private void initialFinishedObserver() {
    if (downloadTasks.size() > 0) {
      allDownloadTaskCompleted = new BooleanBinding() {
        {
          downloadTasks.stream().map(DownloadTask::statusProperty).forEach(this::bind);
        }

        @Override
        protected boolean computeValue() {
          // 假如是双平面均可升级，允许用户直升机其中一个。
          if (project.isFabricUpgradeRequired() && project.isBaseUpgradeRequired()) {
            final List<DownloadTask> collect = downloadTasks
                .stream()
                .filter(task -> task.statusProperty().isNotEqualTo(DownloadTask.Status.Completed).get())
                .collect(Collectors.toList());
            if (collect.isEmpty()) {
              return true;
            }
            if (collect.size() == 1) {
              final DownloadTask downloadTask = collect.get(0);
              final String software = downloadTask.softwareProperty().get();
              return software.equalsIgnoreCase(Plane.Base.name()) || software.equalsIgnoreCase(Plane.Fabric.name());
            }
            return false;
          } else {
            return downloadTasks.stream().allMatch(task ->
                task.statusProperty().isEqualTo(DownloadTask.Status.Completed).get());
          }
        }
      };

      allDownloadTaskCompleted.addListener((observable, oldValue, newValue)
          -> SmartRouter.get().nextStepButton().setDisable(!newValue));
    } else {
      SmartRouter.get().nextStepButton().setDisable(false);
    }
  }

  private void initialTipsBox() {
    final boolean hasLimit = downloadTasks.stream().anyMatch((task) -> {
      final InstallPackage installPackage = task.installPackageProperty().get();
      if (installPackage != null && (!Boolean.FALSE.equals(installPackage.getIsLimit())
          || Strings.isNullOrEmpty(installPackage.getDownloadUrl()))) {
        return true;
      }
      return false;
    });

    if (hasLimit) {
      tips.add(0, getString("download.limited"));
    }

    for (int index = 0; index < tips.size(); index++) {
      String tip = tips.get(index);
      Label label = new Label((index + 1) + ". " + tip);
      label.setWrapText(true);
      label.getStyleClass().add("span");
      tipsBox.getChildren().add(label);
    }
  }

  /**
   * 初始化表格数据
   */
  private void initialTableData() {
    // add table data
    if (fabricPackage.isPresent()) {
      fabricDownloadTask = new DownloadTask(fabricPackage.get(), Plane.Fabric.name(),
          fabricPackage.get().getSoftwareVersion(), fabricPackage.get().getDownloadUrl());
    } else if (project.isFabricUpgradeRequired()) {
      // 假如无法找到 Fabric 安装包，但是Fabric又是可安装平面，那么插入一条待上传记录
      fabricDownloadTask = new DownloadTask(null, Plane.Fabric.name(), finalFabricVersion, null);
    }

    if (fabricDownloadTask != null) {
      downloadTasks.add(fabricDownloadTask);
    }

    if (basePackage.isPresent()) {
      baseDownloadTask = new DownloadTask(basePackage.get(), Plane.Base.name(),
          basePackage.get().getSoftwareVersion(), basePackage.get().getDownloadUrl());
    } else if (project.isBaseUpgradeRequired()) {
      // 假如无法找到 Base 安装包，但是 Base 又是可安装平面，那么插入一条待上传记录
      baseDownloadTask = new DownloadTask(null, Plane.Base.name(), finalBaseVersion, null);
    }

    if (baseDownloadTask != null) {
      downloadTasks.add(baseDownloadTask);
    }

    if (cpldPackage.isPresent()) {
      final Optional<DownloadTask> existDownloadTask = findExistDownloadTask(cpldPackage.get());
      cpldDownloadTask = existDownloadTask.orElse(new DownloadTask(cpldPackage.get(), CPLD,
          cpldPackage.get().getCpldVersion(), cpldPackage.get().getDownloadUrl()));
    } else if (project.getSolution().getCPLD().getUpgrade()) {
      cpldDownloadTask = new DownloadTask(null, CPLD,
          matchedPackage.getCpldVersion(), null);
    }

    if (cpldDownloadTask != null && !downloadTasks.contains(cpldDownloadTask)) {
      downloadTasks.add(cpldDownloadTask);
    }

    if (bmcPackage.isPresent()) {
      final Optional<DownloadTask> existDownloadTask = findExistDownloadTask(bmcPackage.get());
      bmcDownloadTask = existDownloadTask.orElse(new DownloadTask(bmcPackage.get(), BMC,
          bmcPackage.get().getBmcVersion(), bmcPackage.get().getDownloadUrl()));
    } else if (project.getSolution().getBMC().getUpgrade()) {
      bmcDownloadTask = new DownloadTask(null, BMC, matchedPackage.getBmcVersion(), null);
    }

    if (bmcDownloadTask != null && !downloadTasks.contains(bmcDownloadTask)) {
      downloadTasks.add(bmcDownloadTask);
    }

    downloadTable.setItems(downloadTasks);

    // setup download table height
    final int rowNumber = downloadTasks.size();
    final int tableHeight = (rowNumber == 0 ? 4 : rowNumber + 1) * 46 - 4;
    downloadTable.setMinHeight(tableHeight);
    downloadTable.setMaxHeight(tableHeight);
    downloadTable.setPrefHeight(tableHeight);
  }

  private Optional<DownloadTask> findExistDownloadTask(InstallPackage installPackage) {
    return downloadTasks.stream().filter((Predicate<DownloadTask>)
        task -> installPackage.equals(task.installPackageProperty().get())).findFirst();
  }

  /**
   * find all required install package for current project
   */
  private void initialInstallPackages() {
    final Switch switch0 = project.getSwitch0();
    final String boardType = switch0.getBoardType();
    final Solution.Upgrade fabric = project.getSolution().getFabric();
    final Solution.Upgrade base = project.getSolution().getBase();

    // find fabric package
    if (project.isFabricUpgradeRequired()) {
      log.info("Fabric plane upgrade required, find install package now");
      // use fabric specified software version by default else defective's software version
      finalFabricVersion = Strings.isNullOrEmpty(fabric.getVersion()) ?
          project.getDefective().getSoftwareVersion() : fabric.getVersion();
      fabricPackage = SmartDatabase.get().getInstallPackage(boardType, Plane.Fabric, finalFabricVersion);
      if (!fabricPackage.isPresent()) {
        log.error("No Fabric plane install package found, please check db");
        tips.add(String.format(getString("download.package.not.found"), Plane.Fabric.name()));
        //  showDialog(Models.alert(root(), "common.title.db.exception", "download.no.fabric.package.found"));
      } else {
        log.info("Fabric install package found: {}", fabricPackage.get());
      }
    }

    // find base package
    if (project.isBaseUpgradeRequired()) {
      log.info("Base plane upgrade required, find install package now");
      // use fabric specified software version by default else defective's software version
      finalBaseVersion = Strings.isNullOrEmpty(base.getVersion()) ?
          project.getDefective().getSoftwareVersion() : base.getVersion();
      basePackage = SmartDatabase.get().getInstallPackage(boardType, Plane.Base, finalBaseVersion);
      if (!basePackage.isPresent()) {
        log.error("No Base plane install package found, please check db");
        tips.add(String.format(getString("download.package.not.found"), Plane.Base.name()));
        // showDialog(Models.alert(root(), "common.title.db.exception", "download.no.base.package.found"));
      } else {
        log.info("Base install package found: {}", basePackage.get());
      }
    }

    // find CPLD package
    if (project.getSolution().getCPLD().getUpgrade()) {
      log.info("CPLD upgrade required, find install package now");
      final String specifiedVersion = project.getSolution().getCPLD().getVersion();
      final String cpldVersion =
          Strings.isNullOrEmpty(specifiedVersion) ? matchedPackage.getCpldVersion() : specifiedVersion;
      log.info("Required CPLD version is: {}", cpldVersion);

      final boolean cpldExistsInFabric = fabricPackage.isPresent()
          && cpldVersion.equalsIgnoreCase(fabricPackage.get().getCpldVersion());
      final boolean cpldExistsInBase = basePackage.isPresent()
          && cpldVersion.equalsIgnoreCase(basePackage.get().getCpldVersion());
      if (cpldExistsInFabric) {
        cpldPackage = fabricPackage;
        log.info("CPLD already exist in fabric install package");
      } else if (cpldExistsInBase) {
        cpldPackage = basePackage;
        log.info("CPLD already exist in base install package");
      }

      if (!cpldPackage.isPresent()) {
        log.info("CPLD package not exists in both fabric(if) and base(if) package");
        // find cpld package according to the defective cpld version (greater than)
        if (project.isFabricUpgradeRequired()) {
          log.info("Try to find cpld package from other fabric install package");
          cpldPackage = SmartDatabase.get().getCpldInstallPackage(boardType, Plane.Fabric, cpldVersion);
        } else if (project.isBaseUpgradeRequired() && !cpldPackage.isPresent()) {
          log.info("Try to find cpld package from other base install package");
          cpldPackage = SmartDatabase.get().getCpldInstallPackage(boardType, Plane.Base, cpldVersion);
        }

        if (!cpldPackage.isPresent()) {
          log.error("No CPLD install package found, please check db");
          tips.add(String.format(getString("download.package.not.found"), CPLD));
        } else {
          log.info("CPLD install package found: {}", cpldPackage.get());
          // showDialog(Models.alert(root(), "common.title.db.exception", "download.no.cpld.package.found"));
        }
      }
    }

    // find BMC package
    if (project.getSolution().getBMC().getUpgrade()) {
      log.info("BMC upgrade required, find install package now");
      final String matchedBMCVersion = project.getDefective().getMatchedPackage().getBmcVersion();
      log.info("Required BMC version is: {}", matchedBMCVersion);

      final boolean bmcExistsInFabric = fabricPackage.isPresent() &&
          matchedBMCVersion.equalsIgnoreCase(fabricPackage.get().getBmcVersion());
      final boolean bmcExistsInBase = basePackage.isPresent() &&
          matchedBMCVersion.equalsIgnoreCase(basePackage.get().getBmcVersion());
      final boolean bmcExistsInCpld = cpldPackage.isPresent() &&
          matchedBMCVersion.equalsIgnoreCase(cpldPackage.get().getBmcVersion());
      if (bmcExistsInFabric) {
        bmcPackage = fabricPackage;
        log.info("BMC already exist in Fabric install package");
      } else if (bmcExistsInBase) {
        bmcPackage = basePackage;
        log.info("BMC already exist in Base install package");
      } else if (bmcExistsInCpld) {
        bmcPackage = cpldPackage;
        log.info("BMC already exist in CPLD install package");
      }

      if (!bmcPackage.isPresent()) {
        log.info("BMC package not exists in both fabric(if), base(if) and cpld(if) package");
        if (project.isFabricUpgradeRequired()) { // find from fabric plane
          log.info("Try to find bmc[{}] package from other fabric install package", matchedBMCVersion);
          bmcPackage = SmartDatabase.get().getBmcInstallPackage(boardType, Plane.Fabric, matchedBMCVersion);
        }

        if (project.isBaseUpgradeRequired() && !bmcPackage.isPresent()) { // find from base plane if not found in fabric
          log.info("Try to find bmc[{}] package from other base install package", matchedBMCVersion);
          bmcPackage = SmartDatabase.get().getBmcInstallPackage(boardType, Plane.Base, matchedBMCVersion);
        }

        if (!bmcPackage.isPresent()) {
          log.error("No BMC install package found, will create new empty BMC package now");
          tips.add(String.format(getString("download.package.not.found"), BMC));
          // showDialog(Models.alert(root(), "common.title.db.exception", "download.no.bmc.package.found"));
        } else {
          log.info("BMC install package found: {}", bmcPackage.get());
        }
      }
    }
  }

  /**
   * 初始化表格
   */
  private void initializeTableView() {
    downloadTable.setSelectionModel(null);

    softwareColumn.setCellValueFactory(new PropertyValueFactory("software"));
    versionColumn.setCellValueFactory(new PropertyValueFactory("version"));
    packageNameColumn.setCellValueFactory(new PropertyValueFactory("packageName"));
    progressColumn.setCellValueFactory(new PropertyValueFactory("progress"));

    softwareColumn.setCellFactory(TextFieldTableCell.<DownloadTask>forTableColumn());
    versionColumn.setCellFactory(TooltipTextFieldTableCell.<DownloadTask>forTableColumn());
    packageNameColumn.setCellFactory(TooltipTextFieldTableCell.<DownloadTask>forTableColumn());
    progressColumn.setCellFactory(ProgressBarTableCell.<DownloadTask>forTableColumn());
    buttonsColumn.setCellFactory(param -> new TableCell<DownloadTask, Void>() {
      private final Button download = new Button(getString("button.download"));
      private final Button upload = new Button(getString("button.upload"));
      private final Button copy = new Button(getString("button.copy"));
      private final Button limit = new Button(getString("button.limit"));
      private final Button noMatch = new Button(getString("button.no.match"));
      private final HBox actionBox = new HBox();

      {
        limit.setDisable(true);
        noMatch.setDisable(true);
        actionBox.getStyleClass().add("action-box");

        JavaFxObservable.eventsOf(upload, MouseEvent.MOUSE_CLICKED)
            .throttleFirst(500, TimeUnit.MILLISECONDS)
            .subscribe((e) -> {
              DownloadTask downloadTask = getTableView().getItems().get(getIndex());
              uploadPackage(downloadTask);
            });
        JavaFxObservable.eventsOf(download, MouseEvent.MOUSE_CLICKED)
            .throttleFirst(500, TimeUnit.MILLISECONDS)
            .subscribe((e) -> {
              DownloadTask downloadTask = getTableView().getItems().get(getIndex());
              downloadPackage(downloadTask);
            });
        JavaFxObservable.eventsOf(copy, MouseEvent.MOUSE_CLICKED)
            .throttleFirst(500, TimeUnit.MILLISECONDS)
            .subscribe((e) -> {
              DownloadTask downloadTask = getTableView().getItems().get(getIndex());
              final Clipboard clipboard = Clipboard.getSystemClipboard();
              final ClipboardContent content = new ClipboardContent();
              content.putString(downloadTask.urlProperty().get());
              clipboard.setContent(content);
              Toast.of(root(), getString("download.copied.to.clipboard")).show();
            });
      }

      @Override
      protected void updateItem(Void item, boolean empty) {
        super.updateItem(item, empty);
        if (!empty) {
          final DownloadTask task = getTableView().getItems().get(getIndex());
          if (task.installPackageProperty().isNotNull().get()) {
            if (task.urlProperty().isNotEmpty().get()
                && Boolean.FALSE.equals(task.installPackageProperty().get().getIsLimit())) { // download button
              download.disableProperty().bind(task.statusProperty().isNotEqualTo(DownloadTask.Status.Pending));
              download.textProperty().bind(new StringBinding() {
                {
                  bind(task.progressProperty());
                }

                @Override
                protected String computeValue() {
                  final double progress = task.progressProperty().get();
                  if (progress < 1 && progress > 0) {
                    return getString("button.downloading");
                  } else if (progress == 1) {
                    return getString("button.downloaded");
                  } else {
                    return getString("button.download");
                  }
                }
              });
              actionBox.getChildren().add(download);
            } else { // download limited button
              actionBox.getChildren().add(limit);
            }
          } else {
            actionBox.getChildren().add(noMatch);
          }

          // upload button
          actionBox.getChildren().add(upload);

          // copy button
          if (task.urlProperty().isNotEmpty().get()) {
            actionBox.getChildren().add(copy);
          }
        }
        setGraphic(empty ? null : actionBox);
      }
    });
  }

  /**
   * 上传安装包
   */

  private void uploadPackage(DownloadTask downloadTask) {
    FileChooser chooser = new FileChooser();
    chooser.setTitle(String.format(getString("download.upload.file.chooser.title"),
        downloadTask.softwareProperty().get()));
    chooser.setInitialDirectory(FileSystemView.getFileSystemView().getHomeDirectory());

    String ext = "*.*";
    final InstallPackage installPackage = downloadTask.installPackageProperty().get();
    if (installPackage != null && !Strings.isNullOrEmpty(installPackage.getPackageName())) {
      String packageName = installPackage.getPackageName().trim();
      ext = "*." + FilenameUtils.getExtension(packageName);
    } else if (Lists.newArrayList(CPLD, BMC).contains(downloadTask.softwareProperty().get())) {
      ext = "*.hpm";
    }

    String description = String.format("Install Package(%s)", ext);
    chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(description, ext));

    File file = chooser.showOpenDialog(SmartDataBus.get().getStage());
    if (file != null) {
      try {
        // cancel all tasks
        downloadTasks.stream().filter((task) -> {
          final String packageName = task.packageNameProperty().get();
          if (!Strings.isNullOrEmpty(packageName)) {
            return packageName.equalsIgnoreCase(downloadTask.packageNameProperty().get());
          }
          return false;
        }).forEach(DownloadTask::dispose);

        File destFile = getDestFile(downloadTask);
        String destFilePath = destFile.getAbsolutePath();
        if (destFile.isDirectory()) {
          final String fileName = file.getName();
          destFilePath = destFilePath + File.separator + fileName;
          FileUtils.copyFile(file, new File(destFilePath));
          // downloadTask.packageNameProperty().set(fileName);
        } else {
          FileUtils.copyFile(file, destFile);
        }

        onDownloadCompleted(downloadTask, destFilePath);
      } catch (IOException e) {
        log.error("Failed to upload file", e);
      }
    }
  }

  /**
   * download package
   */
  private void downloadPackage(final DownloadTask downloadTask) {
    final String downloadUrl = downloadTask.urlProperty().get();
    final File destFile = getDestFile(downloadTask);
    if (destFile.exists() && destFile.isFile() &&
        destFile.getName().equals(downloadTask.packageNameProperty().get())) {
      onDownloadCompleted(downloadTask, destFile.getAbsolutePath());
      return; // file exists
    }

    final DisposableObserver<RxOkHttp.Progress> observer = new DisposableObserver<RxOkHttp.Progress>() {
      @Override
      public void onStart() {
        downloadTask.statusProperty().set(DownloadTask.Status.Downloading);
        updateDownloadTasksWithSamePackage(downloadTask);
      }

      @Override
      public void onNext(RxOkHttp.Progress progress) {
        final double p = progress.getProgress();
        log.debug("download {}, progress: {}", downloadTask.packageNameProperty().get(), p);
        downloadTask.progressProperty().set(p);
        updateDownloadTasksWithSamePackage(downloadTask);
      }

      @Override
      public void onError(Throwable e) {
        destFile.delete();
      }

      @Override
      public void onComplete() {
        onDownloadCompleted(downloadTask, destFile.getAbsolutePath());
      }
    };

    RxOkHttp.get().downloadFile(downloadUrl, destFile)
        .throttleFirst(5, TimeUnit.SECONDS)
        .doOnDispose(() -> {
          log.info("cancel download, delete temp file & reset download task state now");
          downloadTask.progressProperty().set(0);
          downloadTask.statusProperty().set(DownloadTask.Status.Pending);
        })
        .subscribeOn(Schedulers.io())
        .observeOn(JavaFxScheduler.platform()).subscribe(observer);

    downloadTask.setDisposable(observer);
  }

  private void onDownloadCompleted(DownloadTask downloadTask, String absolutePath) {
    downloadTask.setLocalFileUrl(absolutePath);
    downloadTask.progressProperty().set(1D);
    downloadTask.statusProperty().set(DownloadTask.Status.Completed);
    updateDownloadTasksWithSamePackage(downloadTask);
  }

  /**
   * 更新相同包名的软件包状态
   */
  private void updateDownloadTasksWithSamePackage(final DownloadTask downloadTask) {
    downloadTasks.stream().filter((task) -> {
      if (task != downloadTask) {
        final String packageName = task.packageNameProperty().get();
        if (!Strings.isNullOrEmpty(packageName)) {
          return packageName.equalsIgnoreCase(downloadTask.packageNameProperty().get());
        }
      }
      return false;
    }).forEach((task) -> {
      task.setLocalFileUrl(downloadTask.getLocalFileUrl());
      task.progressProperty().set(downloadTask.progressProperty().get());
      task.statusProperty().set(downloadTask.statusProperty().get());
    });
  }

  /**
   * 下载文件路径,假如无法从downloadTask中获取到待下载的文件名，那么只返回下载目录
   *
   * @return download file path if package-name exists in download-task else download folder
   */
  private File getDestFile(DownloadTask downloadTask) {
    final InstallPackage installPackage = downloadTask.installPackageProperty().get();
    if (installPackage != null && !Strings.isNullOrEmpty(installPackage.getPackageName())) {
      final Project project = SmartDataBus.get().getProject();
      final String fileName = installPackage.getPackageName().trim();
      final String destFilePath = project.home().getAbsolutePath() + File.separator + fileName;
      return new File(destFilePath);
    } else {
      return new File(project.home().getAbsolutePath());
    }
  }

  @Override
  public Observable<Boolean> onLeave() {
    downloadTasks.stream().forEach(DownloadTask::dispose);
    return super.onLeave();
  }

  @Override
  public Observable<Boolean> onFinish() {
    final Project project = SmartDataBus.get().getProject();
    final Project.DownloadPackages downloadPackages = project.getDownloadPackages();

    // 处理下载包数据
    downloadPackages.setFabric(fabricDownloadTask != null ? new DownloadPackage(fabricDownloadTask) : null);
    downloadPackages.setBase(baseDownloadTask != null ? new DownloadPackage(baseDownloadTask) : null);
    if (cpldDownloadTask != null) {
      if (cpldDownloadTask.softwareProperty().get().equals(CPLD)) {
        downloadPackages.setCpld(new DownloadPackage(cpldDownloadTask));
      } else {
        final String cpldVersion = cpldDownloadTask.installPackageProperty().get().getCpldVersion();
        downloadPackages.setCpld(new DownloadPackage(cpldDownloadTask, CPLD, cpldVersion));
      }
    }
    if (bmcDownloadTask != null) {
      if (bmcDownloadTask.softwareProperty().get().equals(BMC)) {
        downloadPackages.setBmc(new DownloadPackage(bmcDownloadTask));
      } else {
        final String bmcVersion = bmcDownloadTask.installPackageProperty().get().getBmcVersion();
        downloadPackages.setBmc(new DownloadPackage(bmcDownloadTask, BMC, bmcVersion));
      }
    }

    return Observable.just(downloadTasks.size() == 0 || allDownloadTaskCompleted.get());
  }
}
